﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Xml;
using TomanuExtensions;
using TomanuExtensions.Utils;
using AmiEmuLib.AmigaConfiguration.ChipsetConfig;

namespace AmiEmuLib.AmigaConfiguration.CoreConfig
{
    /// <summary>
    /// CPU configuration.
    /// </summary>
    [DebuggerDisplay("Model = {Model}")]
    public class CPU : XmlBase
    {
        /// <summary>
        /// CPU model.
        /// </summary>
        public CPUModel Model;

        /// <summary>
        /// Only for compatibility with WinUAE.
        /// </summary>
        public JIT JIT;

        /// <summary>
        /// For cycle exact use Frequency to regulate amiga speed. In adjustable mode use 
        /// AdjustHostCPULoad for CPU load regulations.
        /// </summary>
        public CPUSpeed Speed; 

        /// <summary>
        /// Use in CPUSpeed.Adjustable mode.
        /// </summary>
        public int AdjustHostCPULoad;

        /// <summary>
        /// Should we simulate prefetch. Probably should be used only for A500 and its programs. 
        /// Newer programs shoudl be aware of cache, self-modified code and that CPU speed may vary.
        /// </summary>
        public bool Prefetch;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="a_reader"></param>
        public CPU(XmlReader a_reader)
            : base(a_reader)
        {
        }

        /// <summary>
        /// Shoudl be true only for 68000, 680EC20. That is for any raw model instead A3000, A4000.
        /// </summary>
        public bool AddressSpace24Bits
        {
            get
            {
                return (Model == CPUModel.MC68000) || (Model == CPUModel.MC68EC020);
            }
        }

        /// <summary>
        /// True if MMU is build in this cpu model.
        /// </summary>
        public MMUModel BuildInMMU
        {
            get
            {
                switch (Model)
                {
                    case CPUModel.MC68030: return MMUModel.MC68030;
                    case CPUModel.MC68040: return MMUModel.MC68040;
                    case CPUModel.MC68060: return MMUModel.MC68060;
                    case CPUModel.MC68LC040: return MMUModel.MC68040;
                    case CPUModel.MC68LC060: return MMUModel.MC68060;
                    default: return MMUModel.None;
                }
            }
        }

        /// <summary>
        /// Does FPU is build in this cpu model.
        /// </summary>
        public FPUModel BuildInFPU
        {
            get
            {
                switch (Model)
                {
                    case CPUModel.MC68040: return FPUModel.MC68040;
                    case CPUModel.MC68060: return FPUModel.MC68060;
                    default: return FPUModel.None;
                }
            }
        }

        protected override void ReadXml(XmlReader a_reader)
        {
            Model = a_reader.GetAttributeEnum<CPUModel>("Model");

            a_reader.ReadStartElement(GetType().Name);

            JIT = new JIT(a_reader);
            Speed = a_reader.ReadElementContentAsEnum<CPUSpeed>("Speed");
            AdjustHostCPULoad = a_reader.ReadElementContentAsInt("AdjustHostCPULoad");
            Prefetch = a_reader.ReadElementContentAsBoolean("Prefetch");

            a_reader.ReadEndElement();
        }

        public override void WriteXml(XmlWriter a_writer)
        {
            a_writer.WriteStartElement(GetType().Name);

            a_writer.WriteAttribute("Model", Model);
            JIT.WriteXml(a_writer);
            a_writer.WriteElement("Speed", Speed);
            a_writer.WriteElement("AdjustHostCPULoad", AdjustHostCPULoad);
            a_writer.WriteElement("Prefetch", Prefetch);

            a_writer.WriteEndElement();
        }
    }
}
